package tools.project.controller {
	import com.greensock.events.LoaderEvent;
	import com.greensock.loading.SWFLoader;
	import com.greensock.loading.data.SWFLoaderVars;

	import flash.desktop.NativeProcess;
	import flash.desktop.NativeProcessStartupInfo;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.NativeProcessExitEvent;
	import flash.events.ProgressEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	import flash.utils.clearInterval;
	import flash.utils.getTimer;
	import flash.utils.setInterval;

	import ghostcat.fileformat.png.PNGEncoder;
	import ghostcat.operation.FunctionOper;
	import ghostcat.operation.Queue;

	import kiwi.debug.Log;
	import kiwi.util.ArrayUtils;
	import kiwi.util.sprintf;
	import kiwi.util.bitmap.BitmapUtil;
	import kiwi.util.time.Time;

	import org.aswing.JOptionPane;
	import org.robotlegs.mvcs.Command;

	import tools.event.ProjectEvent;
	import tools.model.ActionFrameInfo;
	import tools.model.ActionInfo;
	import tools.model.EditorConfig;
	import tools.model.FrameInfo;
	import tools.model.TextureTypeEnum;
	import tools.model.TileInfo;
	import tools.utils.MaxRectsBinPack;

	public class Ani2AniCommand extends Command {
		[Inject]
		public var config : EditorConfig;
		[Inject]
		public var event : ProjectEvent;
		private var rootDir : File;
		private var queueList : Array;
		private var rootDirFileList : Array;
		private var errorFileList : Array;
		private var jsflList : Array;
		private var startTime : int;

		override public function execute() : void {
			super.execute();
			if (event.file) {
				rootDir = event.file;
				onSelected();
			} else {
				JOptionPane.showInputDialog("提示", "打开JSFL的所在目录", function(path : String) : void {
					if (!path) {
						return;
					}
					rootDir = File.applicationDirectory.resolvePath(path);
					if (!rootDir.exists) {
						Log.alert("目录不存在");
					} else if (!rootDir.isDirectory) {
						Log.alert("请选择文件夹");
					} else {
						onSelected();
					}
				}, "e:\\Desktop\\body");
			}
		}

		private function onSelected(event : Event = null) : void {
			if (config.flash == null) {
				Log.alert("Flash没有找到");
				return;
			}
			var flash : File = File.applicationDirectory.resolvePath(config.flash);
			if (!flash.exists) {
				Log.alert("Flash.exe没有找到");
				return;
			}

			rootDirFileList = new Array();
			errorFileList = new Array();
			pachRun(rootDir);
			startTime = getTimer();
			trace(rootDirFileList.length);
			loadAndConventFile(rootDirFileList.pop() as File);
		}

		private var dicList : Array = ["body", "horse", "pet", "weapon"];

		private function pachRun(file : File) : void {
			for each (var childFile:File in file.getDirectoryListing()) {
				if (childFile.isDirectory && dicList.indexOf(childFile.name) >= 0) {
					pachRun(childFile);
				} else if (TextureTypeEnum.CONVENT_STR.indexOf(childFile.name.substring(childFile.name.indexOf("_") + 1, childFile.name.indexOf("."))) >= 0) {
					continue;
				} else {
					if (childFile.type == ".ani") {
						rootDirFileList.push(childFile);
					}
				}
			}
		}

		private var tempFile : File;

		private function loadAndConventFile(file : File) : void {
			try {
				trace("================================================等待队列:" + rootDirFileList.length + "|用时:" + (getTimer() - startTime) / 1000);
				tempFile = file;
				var loaderVars : SWFLoaderVars = new SWFLoaderVars();
				loaderVars.onComplete(handleComplete);

				loaderVars.onError(onErrorFun);
				loaderVars.onIOError(onErrorFun);
				loaderVars.onSecurityError(onErrorFun);
				loaderVars.onFail(onErrorFun);

				var loader : SWFLoader = new SWFLoader(file.nativePath, loaderVars);
				loader.addEventListener(LoaderEvent.ERROR, onErrorFun);
				loader.addEventListener(LoaderEvent.IO_ERROR, onErrorFun);
				loader.load();
			} catch(error : Error) {
				trace("========================catch=ERROR==============================" + tempFile.name);
			}
		}

		private function onErrorFun(event : LoaderEvent) : void {
			trace("=========================ERROR==============================" + tempFile.name);
		}

		private function handleComplete(loaderEvent : LoaderEvent) : void {
			var textureClz : Class = (loaderEvent.target as SWFLoader).getClass("TEXTURE_" + tempFile.parent.name + "_" + tempFile.name.replace(".ani", ""));
			var textureConfClz : Class = (loaderEvent.target as SWFLoader).getClass("TEXTURE_CONF_" + tempFile.parent.name + "_" + tempFile.name.replace(".ani", ""));
			if (!textureClz) {
				textureClz = (loaderEvent.target as SWFLoader).getClass("TEXTURE_" + tempFile.name.replace(".ani", ""));
				textureConfClz = (loaderEvent.target as SWFLoader).getClass("TEXTURE_CONF_" + tempFile.name.replace(".ani", ""));
			}
			try {
				(loaderEvent.target as SWFLoader).unload();
			} catch(error : Error) {
				trace("========================catch=ERROR==unload=======================" + tempFile.name);
			}
			if (!textureClz) {
				errorFileList.push(tempFile.nativePath);
				gotoNextAni();
				return;
			}
			var source : * = new textureClz;
			var bd : BitmapData = source is Bitmap ? source.bitmapData : source;
			var xml : XML = new XML(new textureConfClz());
			conventXmlAndBd(bd, xml);
		}

		private function gotoNextAni() : void {
			if (rootDirFileList.length > 0) {
				loadAndConventFile(rootDirFileList.pop() as File)
			} else {
				Log.alert("听说是搞完了.");
				if (errorFileList && errorFileList.length > 0) {
					for each (var str:String in errorFileList) {
						trace("ERROR PATH:" + str);
					}
				}
			}
		}

		private function conventXmlAndBd(bd : BitmapData, xml : XML) : void {
			var actions : XMLList = xml.actions[0].action;
			var frames : XMLList = xml.frames[0].frame;
			var tiles : XMLList = xml.tiles[0].tile;

			if (!actions) {
				gotoNextAni();
			} else {
				trace("需要处理的:" + tempFile.name);

				var totleAction : Array = new Array();
				var totleFrame : Array = new Array();
				var totleTile : Array = new Array();

				var action : ActionInfo;
				var frame : ActionFrameInfo;
				var tile : TileInfo;

				for each (var tilexml:XML in tiles) {
					tile = new TileInfo();
					tile.id = tilexml.id;
					tile.source = new Rectangle(tilexml.source.x, tilexml.source.y, tilexml.source.width, tilexml.source.height);
					tile.registration = new Point(tilexml.registration.x, tilexml.registration.y);
					tile.$cached = BitmapUtil.clip(bd, tile.source, false);
					totleTile.push(tile);
				}

				for each (var framexml:XML in frames) {
					frame = new ActionFrameInfo();
					frame.frame = new FrameInfo();
					frame.frame.id = framexml.id;
					var tepArr : Array = String(framexml.tile).split(",");
					if (tepArr.length == 1) {
						frame.frame.tileList = ArrayUtils.find(totleTile, "id", tepArr[0]);
					} else {
						for each (var id:int in tepArr) {
							frame.frame.tileList.push(ArrayUtils.find(totleTile, "id", id));
						}
					}
					totleFrame.push(frame);
				}

				for each (var actxml:XML in actions) {
					action = new ActionInfo();
					action.scale = actxml.scale;
					action.name = actxml.name();

					var frameArr : Array = String(actxml.frame).split(",");
					var frameDurArr : Array = String(actxml.frame_duration).split(",");
					var durIndex : int = 0;
					for each (var frameId:int in frameArr) {
						for (var i : int = 0;i < totleFrame.length;i++) {
							if (ActionFrameInfo(totleFrame[i]).frame.id == frameId) {
								ActionFrameInfo(totleFrame[i]).duration = frameDurArr[durIndex];
								action.frameList.push(totleFrame[i]);
							}
						}
						durIndex++ ;
					}
					totleAction.push(action);
				}
				checkGroup(totleAction, totleFrame, totleTile);
			}
		}

		private function checkGroup(actionList : Array, frameList : Array, tileList : Array) : void {
			// 分类  & check group // 还要判断 是不是一组的

			var eachKeyDic : Dictionary = new Dictionary();
			var keyDic : Dictionary = new Dictionary();

			for each (var actionInfo:ActionInfo in actionList) {
				var acIndex : int = TextureTypeEnum.ACTION_STR.indexOf(actionInfo.name);
				if (acIndex >= 0) {
					if (eachKeyDic[TextureTypeEnum.CONVENT_STR[acIndex]] && eachKeyDic[TextureTypeEnum.CONVENT_STR[acIndex]] is Array) {
						eachKeyDic[TextureTypeEnum.CONVENT_STR[acIndex]] = (eachKeyDic[TextureTypeEnum.CONVENT_STR[acIndex]]  as Array).concat(actionInfo);
					} else {
						eachKeyDic[TextureTypeEnum.CONVENT_STR[acIndex]] = [actionInfo];
						keyDic[TextureTypeEnum.CONVENT_STR[acIndex]] = TextureTypeEnum.CONVENT_STR[acIndex];
					}
				}
			}

			var tempIndex : int = 0;
			for each (var str:String in keyDic) {
				tempIndex++;
			}
			if (tempIndex == 1) {
				// 只有一个
				if (keyDic["stills"]) {
					conventPngAndXml(keyDic, eachKeyDic);
				} else {
					gotoNextAni();
				}
			} else {
				// 绘图 以及 搞xml
				conventPngAndXml(keyDic, eachKeyDic);
			}
		}

		private function conventPngAndXml(keyDic : Dictionary, eachKeyDic : Dictionary) : void {
			jsflList = new Array();

			for each (var arrKey:Object in keyDic) {
				var tempjsflPath : String;

				if (arrKey && eachKeyDic[arrKey] is Array) {
					// result
					var result : XML = <config></config>;
					// tiles部分
					var tiles : XML = <tiles></tiles>;
					// frame部分
					var frames : XML = <frames></frames>;
					// action部分
					var actions : XML = <actions></actions>;

					var pack : MaxRectsBinPack = new MaxRectsBinPack(4096, 4096);
					var tempOP : FileStream;
					var xmlOp : FileStream;
					var xmlFile : File;
					var pngFile : File;
					var canvas : BitmapData = new BitmapData(4096, 4096, true, 0x0);
					canvas.lock();

					for each (var action:ActionInfo in eachKeyDic[arrKey]) {
						actions.appendChild(createXMLByObject("action", {scale:action.scale, name:action.name, frame_duration:ArrayUtils.collect(action.frameList, "duration").join(","), frame:ArrayUtils.collect(ArrayUtils.collect(action.frameList, "frame"), "id").join(",")}));
						for each (var frame:ActionFrameInfo in action.frameList) {
							frames.appendChild(createXMLByObject("frame", {id:frame.frame.id, tile:ArrayUtils.collect(frame.frame.tileList, "id").join(",")}));
							for each (var tile:TileInfo in frame.frame.tileList) {
								var tmp : Rectangle = pack.insert(tile.source.width, tile.source.height, MaxRectsBinPack.METHOD_RECT_BEST_AREA_FIT);
								tiles.appendChild(createXMLByObject("tile", {id:tile.id, source:{x:tmp.x, y:tmp.y, width:tmp.width, height:tmp.height}, registration:{x:tile.registration.x, y:tile.registration.y}}));
								canvas.copyPixels(tile.$cached, tile.$cached.rect, tmp.topLeft, null, null, true);
							}
						}
					}

					result.appendChild(tiles);
					result.appendChild(frames);
					result.appendChild(actions);

					tempjsflPath = tempFile.name.replace(tempFile.type, "") + "_" + arrKey;

					xmlOp = new FileStream();
					xmlFile = File.applicationDirectory.resolvePath(tempFile.parent.nativePath + "/" + tempjsflPath + ".xml");
					xmlOp.open(xmlFile, FileMode.WRITE);
					xmlOp.writeUTFBytes(result.toString());
					xmlOp.close();

					canvas.unlock();
					canvas = BitmapUtil.trim(canvas, null);

					pngFile = File.applicationDirectory.resolvePath(tempFile.parent.nativePath + "/" + tempjsflPath + ".png");

					tempOP = new FileStream();
					tempOP.open(pngFile, FileMode.WRITE);
					tempOP.writeBytes(PNGEncoder.encode(canvas));
					tempOP.close();

					// 生成 分包
					gotoJsft2Ani(tempFile, tempjsflPath);
				}
			}

			conventJsfl2Ani();
		}

		private function createXMLByObject(title : String, obj : *) : XML {
			if (obj is int || obj is Number || obj is String || obj is Boolean || obj is uint) {
				return new XML(sprintf("<%s>%s</%s>", title, obj, title));
			}
			var xml : XML = new XML(sprintf("<%s></%s>", title, title));
			for (var key:String in obj) {
				var subXML : XML;
				if (obj[key] is Array) {
					subXML = new XML(sprintf("<%s></%s>", key, key));
					for each (var subObj:* in obj[key]) {
						subXML.appendChild(createXMLByObject("item", subObj));
					}
				} else {
					subXML = createXMLByObject(key, obj[key]);
				}
				xml.appendChild(subXML);
			}
			return xml;
		}

		private function gotoJsft2Ani(dirPath : File, fileNames : String, quality : int = 80) : void {
			var prefix : String = "_" + dirPath.parent.name + "_" + fileNames;
			var jsfl : String = <![CDATA[
							//pkg(fl.browseForFolderURL("请选择素材文件夹"),80);
							function pkg(folderPath,spriteName,quality){
								var spriteName;
								// 清理输出
								fl.outputPanel.clear();
								// 创建新文件
								fl.createDocument();
								var dom = fl.getDocumentDOM();
								var lib = fl.getDocumentDOM().library;
								// 导入类
								FLfile.write(folderPath+"/ENTRY.as","package{import flash.display.*;public class ENTRY extends MovieClip{TEXTURE_CONF${prefix};TEXTURE${prefix};}}");
								dom.docClass="ENTRY";
								fl.trace("主脚本生成成功");
								FLfile.write(folderPath+"/TEXTURE_CONF${prefix}.as","package{import flash.utils.*;[Embed(source=\""+spriteName+".xml\",mimeType=\"application/octet-stream\")]public class TEXTURE_CONF${prefix} extends ByteArray {}}");
								fl.trace("导出配置文件成功");
								// 打开文件夹
								fl.trace("我擦擦："+folderPath + "/"+spriteName+".png");
								dom.importFile(folderPath + "/"+spriteName+".png");
								fl.trace("导入图片成功");
								lib.selectItem(spriteName+".png");
								// 清场
								dom.selectAll(); 
								dom.deleteSelection();
								// 导出位图链接
								lib.setItemProperty("allowSmoothing",false);
								lib.setItemProperty("linkageExportForAS",true);
								lib.setItemProperty("linkageExportInFirstFrame",true);
								lib.setItemProperty("linkageBaseClass","flash.display.BitmapData");
								lib.setItemProperty("linkageClassName","TEXTURE${prefix}");
								lib.setItemProperty("compressionType","photo");
								lib.setItemProperty("quality",quality);
								fl.trace("导出图片成功");
								
								// 保存配置类
								fl.saveDocument(dom,folderPath+"/"+spriteName+".fla");
								dom.swfJPEGQuality=quality;
								dom.exportSWF(folderPath+"/"+spriteName+".swf",true);
								dom.close();
								FLfile.copy(folderPath+"/"+spriteName+".swf",folderPath+"/"+spriteName+".ani");
								FLfile.remove(folderPath+"/ENTRY.as");
								FLfile.remove(folderPath+"/TEXTURE_CONF${prefix}.as");
								FLfile.remove(folderPath+"/"+spriteName+".fla");
								FLfile.remove(folderPath+"/"+spriteName+".jsfl");
								FLfile.remove(folderPath+"/"+spriteName+".swf");
								FLfile.remove(folderPath+"/"+spriteName+".png");
								FLfile.remove(folderPath+"/"+spriteName+".xml");
			
								//FLfile.remove(folderPath);
							}
						]]>;
			var out : FileStream = new FileStream();
			var jsflFile : File = dirPath.parent.resolvePath(fileNames + ".jsfl");
			jsflList.push(jsflFile);
			out.open(jsflFile, FileMode.WRITE);
			out.writeByte(0xEF);
			out.writeByte(0xBB);
			out.writeByte(0xBF);
			out.writeUTFBytes(jsfl.replace(/\$\{prefix\}/g, prefix));
			out.writeUTFBytes(sprintf("pkg(\"file:///%s\",\"%s\",%d);", dirPath.parent.nativePath.replace(/\\/g, "/"), fileNames, 80));
			out.close();
		}

		private function conventJsfl2Ani() : void {
			var operList : Array = new Array();

			var flash : File = File.applicationDirectory.resolvePath(config.flash);
			for each (var jsflStrs:File in jsflList) {
				operList.push(new TransOper(jsflStrs, flash));
			}

			operList.push(new FunctionOper(gotoNextAni));
			var queue : Queue = new Queue(operList);
			queue.execute();
		}
	}
}
import flash.desktop.NativeProcess;
import flash.desktop.NativeProcessStartupInfo;
import flash.events.Event;
import flash.events.NativeProcessExitEvent;
import flash.events.ProgressEvent;
import flash.filesystem.File;
import flash.utils.clearInterval;
import flash.utils.setInterval;
import flash.utils.setTimeout;

import ghostcat.operation.Oper;

import kiwi.debug.Log;

class TransOper extends Oper {
	private var transFile : File;
	private var flashFile : File;

	public function TransOper(file : File, flash : File) {
		transFile = file;
		flashFile = flash;
	}

	private var interval : uint;

	override public function execute() : void {
		super.execute();

		run(flashFile, [transFile.nativePath], function() : void {
			interval = setInterval(check, 1000);
		}, Log.info, Log.alert);
	}

	private function check() : void {
		if (!transFile.exists) {
			clearInterval(interval);
			result();
		}
	}

	private function run(file : File, arg : Array = null, exitHandler : Function = null, traceHandler : Function = null, errorHandler : Function = null, workingDirectory : File = null) : void {
		var nativeProcessStartupInfo : NativeProcessStartupInfo = new NativeProcessStartupInfo();
		nativeProcessStartupInfo.executable = file;
		nativeProcessStartupInfo.workingDirectory = workingDirectory;
		if (arg) {
			var vector : Vector.<String> = new Vector.<String>();
			vector.push.apply(null, arg);
			nativeProcessStartupInfo.arguments = vector;
		}
		var process : NativeProcess = new NativeProcess();
		if (dataHandler != null) {
			process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, dataHandler);
			process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, dataHandler);
		}
		if (exitHandler != null) {
			process.addEventListener(NativeProcessExitEvent.EXIT, exitHandler);
		}
		try {
			process.start(nativeProcessStartupInfo);
		} catch(error : Error) {
			Log.alert("ani2ani,好像可以忽略");
		}
		return;
		function dataHandler(event : Event) : void {
			var process : NativeProcess = event.currentTarget as NativeProcess;
			var str : String;
			if (event.type == ProgressEvent.STANDARD_OUTPUT_DATA) {
				str = process.standardOutput.readMultiByte(process.standardOutput.bytesAvailable, "gb2312").toString();
				if (traceHandler != null) {
					traceHandler(str);
				}
			} else {
				str = process.standardError.readMultiByte(process.standardError.bytesAvailable, "gb2312").toString();
				if (errorHandler != null) {
					errorHandler(str);
				}
			}
		}
	}
}


